classdef dotsComputableFunction < dotsComputable
    % @class dotsComputableFunction
    % Invoke an arbitrary function to do a computation.
    %
    % @ingroup computable
    
    properties (SetObservable = true)
        % function handle or string function to invoke during compute()
        % @details
        % computeFunction should be a function handle or string function
        % name to pass to the built-in feval().  Since computeFunction may
        % need to be executed on a remote machine, it should have universal
        % scope: computeFunction may be a class static method, but not an
        % instance method; if computeFunction is an anonymous function, it
        % should not refer to any variables or sub-functions in a local
        % workspace.
        % @details
        % computeFunction must return at least one output, the first of
        % which will be stored in computeResult.
        computeFunction;
        
        % cell array of input arguments to pass to computeFunction
        computeInputs = {};
        
        % function handle or string function to invoke before compute()
        % @details
        % prepareFunction should be a function handle or string function
        % name to pass to the built-in feval().  Since prepareFunction may
        % need to be executed on a remote machine, it should have universal
        % scope: prepareFunction may be a class static method, but not an
        % instance method; if prepareFunction is an anonymous function, it
        % should not refer to any variables or sub-functions in a local
        % workspace.
        % @details
        % prepareFunction should not expect any inputs and should not
        % expect any outputs.
        prepareFunction;
    end
    
    methods
        % Constructor takes no arguments.
        function self = dotsComputableFunction
            self = self@dotsComputable;
        end
        
        % Invoke prepareFunction.
        % @deatils
        % Extends the prepareToCompute function of dotsComputable to also
        % invoke prepareFunction.
        function prepareToCompute(self)
            self.prepareToCompute@dotsComputable;
            if ~isempty(self.prepareFunction)
                feval(self.prepareFunction);
            end
        end
        
        % Invoke computeFunction with computeInputs as arguments.
        function result = compute(self)
            if ~isempty(self.computeFunction)
                result = ...
                    feval(self.computeFunction, self.computeInputs{:});
            else
                result = [];
            end
            self.computeResult = result;
        end
    end
end